#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sxml_parse.h"
#include "sxml_node.h"

////////////////////////////////////////////////////////////////////////////////
//Local variables
static struct _sxmlNode sxml_root = {NULL, NULL, 0,
    NULL, NULL, NULL, NULL,
    NULL};
static struct _sxmlNode* sxml_node_iterator = &sxml_root;

//Local interfaces
static void* sxml_malloc(int size);
static void sxml_free(void* p);
static char* sxml_duplicate_string(const char* s);
static void sxml_release_string(char* s);
static void sxml_callback_meta(int level, const char* meta);
static void sxml_callback_tags(int level, const char* tag);
static void sxml_callback_data(int level, const char* data);
static void sxml_callback_prop(int level, const char* property, const char* value);

////////////////////////////////////////////////////////////////////////////////
#ifdef SXML_MEM_LEAK_CHECK
static int* sxml_memory_leak[1024] = {NULL};

void sxml_memory_save(void* p)
{
    int i = 0;
    for (i = 0;i < 1024;i++) {
        if (sxml_memory_leak[i] == NULL) {
            break;
        }
    }

    if (i < 1024) {
        sxml_memory_leak[i] = p;
    } else {
        printf("Error : too many malloc!\n");
    }
}

void sxml_memory_clear(void* p)
{
    int i = 0;
    for (i = 0;i < 1024;i++) {
        if (sxml_memory_leak[i] == p) {
            break;
        }
    }

    if (i < 1024) {
        sxml_memory_leak[i] = NULL;
    } else {
        printf("Error : %p not register!\n", p);
    }
}

void sxml_memory_check()
{
    int i = 0;
    char bleak = 0;
    printf("sxml_memory_check start.\n");
    for (i = 0;i < 1024;i++) {
        if (sxml_memory_leak[i] != NULL) {
            bleak = 1;
            printf("Leak : 0x%p = %s\n", sxml_memory_leak[i], sxml_memory_leak[i]);
        }
    }
    if (!bleak) {
        printf("sxml_memory_leak not any leak.\n");
    }
}
#endif

void* sxml_malloc(int size)
{
    void* p = malloc(size);
#ifdef SXML_MEM_LEAK_CHECK
    sxml_memory_save(p);
#endif
    return p;
}

void sxml_free(void* p)
{
#ifdef SXML_MEM_LEAK_CHECK
    sxml_memory_clear(p);
#endif
    free(p);
}

char* sxml_duplicate_string(const char* s)
{
    int len = 0;
    char* p = NULL;

    if ((s == NULL) || ((len = strlen(s)) == 0)) {
        return NULL;
    }

    p = (char*)sxml_malloc(sizeof(char) * (len + 1));
    memcpy(p, s, len + 1);
    return p;
}

void sxml_release_string(char* s)
{
    if (s != NULL) {
        sxml_free(s);
        s = NULL;
    }
}

void sxmlWalkAttr(struct _sxmlAttr* p)
{
    int i = 0;
    
    if (p == NULL) {
        return;
    }

    for (i = 0;i < p->parent->level;i++) {
        printf("  ");
    }
    printf("+");

    if (p->name != NULL) {
        printf("sxmlAttr (%s", p->name);
    } else {
        printf("sxmlAttr ((NULL)");
    }

    if (p->value != NULL) {
        printf(":%s)\n", p->value);
    } else {
        printf(")\n");
    }

    sxmlWalkAttr(p->next);
}

void sxmlWalkNode(struct _sxmlNode* p)
{
    int i = 0;

    if (p == NULL) {
        return;
    }

    if (p->level == 0) {
        printf("sxmlNode Root\n");
    } else {
        for (i = 0;i < p->level;i++) {
            printf("  ");
        }

        if (p->name != NULL) {
            printf("sxmlNode (%s", p->name);
        } else {
            printf("sxmlNode ((NULL)");
        }

        if (p->value != NULL) {
            printf(":%s)\n", p->value);
        } else {
            printf(")\n");
        }

        sxmlWalkAttr(p->properties);
    }

    sxmlWalkNode(p->children);
    sxmlWalkNode(p->next);
}

void sxmlFreeAttr(struct _sxmlAttr* p)
{
    if (p == NULL) {
        return;
    }
    
    sxmlFreeAttr(p->next);
    p->next = NULL;
    p->prev = NULL;
    p->parent = NULL;

    sxml_release_string(p->name);
    sxml_release_string(p->value);
    sxml_free(p);
}

void sxmlFreeNode(struct _sxmlNode* p)
{
    if (p == NULL) {
        return;
    }

    sxmlFreeAttr(p->properties);
    p->properties = NULL;

    sxmlFreeNode(p->children);
    p->children = NULL;
    p->parent = NULL;

    sxmlFreeNode(p->next);
    p->next = NULL;
    p->prev = NULL;

    sxml_release_string(p->name);
    sxml_release_string(p->value);
    sxml_free(p);
}

void sxml_callback_meta(int level, const char* meta)
{
    printf("META: %s\n", meta);
}

void sxml_callback_tags(int level, const char* tag)
{
    if (!sxml_node_iterator) {
        return;
    }

    if (tag[0] == '/') {
        sxml_node_iterator = sxml_node_iterator->parent;
        return;
    }

    if (sxml_node_iterator->level == level) {
        while (sxml_node_iterator->next != NULL) {
            sxml_node_iterator = sxml_node_iterator->next;
        }
        sxml_node_iterator->next = (struct _sxmlNode*)sxml_malloc(sizeof(struct _sxmlNode));
        sxml_node_iterator->next->parent = sxml_node_iterator->parent;
        sxml_node_iterator->next->prev   = sxml_node_iterator;
        sxml_node_iterator->next->next   = NULL;
        sxml_node_iterator->next->children      = NULL;
        sxml_node_iterator->next->properties    = NULL;
        sxml_node_iterator->next->value  = NULL;
        sxml_node_iterator->next->level  = level;
        sxml_node_iterator->next->name   = sxml_duplicate_string(tag);
        sxml_node_iterator = sxml_node_iterator->next;
    } else if (sxml_node_iterator->level < level) {
        if (sxml_node_iterator->children == NULL) {
            sxml_node_iterator->children = (struct _sxmlNode*)sxml_malloc(sizeof(struct _sxmlNode));
            sxml_node_iterator->children->parent = sxml_node_iterator;
            sxml_node_iterator->children->prev   = NULL;
            sxml_node_iterator->children->next   = NULL;
            sxml_node_iterator->children->children      = NULL;
            sxml_node_iterator->children->properties    = NULL;
            sxml_node_iterator->children->value  = NULL;
            sxml_node_iterator->children->level  = level;
            sxml_node_iterator->children->name   = sxml_duplicate_string(tag);
            sxml_node_iterator = sxml_node_iterator->children;
        } else {
            sxml_node_iterator = sxml_node_iterator->children;
            while (sxml_node_iterator->next != NULL) {
                sxml_node_iterator = sxml_node_iterator->next;
            }
            sxml_node_iterator->next = (struct _sxmlNode*)sxml_malloc(sizeof(struct _sxmlNode));
            sxml_node_iterator->next->parent = sxml_node_iterator->parent;
            sxml_node_iterator->next->prev = sxml_node_iterator;
            sxml_node_iterator->next->next = NULL;
            sxml_node_iterator->next->children      = NULL;
            sxml_node_iterator->next->properties    = NULL;
            sxml_node_iterator->next->value  = NULL;
            sxml_node_iterator->next->level  = level;
            sxml_node_iterator->next->name   = sxml_duplicate_string(tag);
            sxml_node_iterator = sxml_node_iterator->next;
        }
    } else if (sxml_node_iterator->level > level) {//This branch may not reach!
        sxml_node_iterator = sxml_node_iterator->parent;
        sxml_node_iterator->next = (struct _sxmlNode*)sxml_malloc(sizeof(struct _sxmlNode));
        sxml_node_iterator->next->parent = sxml_node_iterator->parent;
        sxml_node_iterator->next->prev   = sxml_node_iterator;
        sxml_node_iterator->next->next   = NULL;
        sxml_node_iterator->next->children      = NULL;
        sxml_node_iterator->next->properties    = NULL;
        sxml_node_iterator->next->value  = NULL;
        sxml_node_iterator->next->level  = level;
        sxml_node_iterator->next->name   = sxml_duplicate_string(tag);
        sxml_node_iterator = sxml_node_iterator->next;
    } else {//This branch must not reach!
        printf("Error!");
    }
}

void sxml_callback_data(int level, const char* data)
{
    if (!sxml_node_iterator) {
        return;
    }

    if (sxml_node_iterator->value != NULL) {
        sxml_release_string(sxml_node_iterator->value);
    }
    sxml_node_iterator->value = sxml_duplicate_string(data);
}

void sxml_callback_prop(int level, const char* property, const char* value)
{
    struct _sxmlAttr* sxml_attr_iterator = NULL;

    if (sxml_node_iterator == NULL) {
        return;
    }

    //Iterator to last attr and append new attr
    if (sxml_node_iterator->properties == NULL) {
        sxml_attr_iterator = (struct _sxmlAttr*)sxml_malloc(sizeof(struct _sxmlAttr));
        sxml_attr_iterator->prev = NULL;
        sxml_node_iterator->properties = sxml_attr_iterator;
    } else {
        sxml_attr_iterator = sxml_node_iterator->properties;
        while (sxml_attr_iterator->next != NULL) {
            sxml_attr_iterator = sxml_attr_iterator->next;
        }
        sxml_attr_iterator->next = (struct _sxmlAttr*)sxml_malloc(sizeof(struct _sxmlAttr));
        sxml_attr_iterator->next->prev = sxml_attr_iterator;
        sxml_attr_iterator = sxml_attr_iterator->next;
    }

    //Save property and value.
    sxml_attr_iterator->name  = sxml_duplicate_string(property);
    sxml_attr_iterator->value = sxml_duplicate_string(value);
    sxml_attr_iterator->parent = sxml_node_iterator;
    sxml_attr_iterator->next  = NULL;
}

struct _sxmlNode* sxmlGetRootElement(const char* xmlfile)
{
    struct _sxmlNode* p = NULL;

    //Init callback
    sxmlInitCallback(sxml_callback_meta, sxml_callback_tags,
            sxml_callback_data, sxml_callback_prop);
    sxmlParseFromFile(xmlfile);

    //Build return value
    p = sxml_root.children;
    sxml_root.children = NULL;
    sxml_node_iterator = &sxml_root;

    return p;
}

const char* sxmlNodeGetContent(struct _sxmlNode* p)
{
    if (p == NULL) {
        return NULL;
    }

    return p->value;
}

int sxmlHasProp(struct _sxmlNode* p, const char* name)
{
    struct _sxmlAttr* sxml_attr_iterator = NULL;

    if (p == NULL) {
        return 0;
    }

    sxml_attr_iterator = p->properties;
    while (sxml_attr_iterator != NULL) {
        if (strcmp(sxml_attr_iterator->name, name) == 0) {
            return 1;
        }
        sxml_attr_iterator = sxml_attr_iterator->next;
    }

    return 0;
}

const char* sxmlGetProp(struct _sxmlNode* p, const char* name)
{
    struct _sxmlAttr* sxml_attr_iterator = NULL;

    if (p == NULL) {
        return NULL;
    }

    sxml_attr_iterator = p->properties;
    while (sxml_attr_iterator != NULL) {
        if (strcmp(sxml_attr_iterator->name, name) == 0) {
            return sxml_attr_iterator->value;
        }
        sxml_attr_iterator = sxml_attr_iterator->next;
    }

    return NULL;
}

